/********************************************
 * 功能说明: 平台校验工程类
 * 模块名称: 校验模块
 * 系统名称: 互联网金融平台
 * 软件版权: 北京银杉金服科技有限公司
 * 系统版本: 1.0.0
 * 开发人员: zhaorq
 * 开发时间: 2017年5月12日 上午11:38:29
 * 审核人员:
 * 相关文档:
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.hyacinth.util.validator;

import com.hyacinth.constant.ErrorCodeEnum;
import com.hyacinth.exception.BusinessException;
import com.hyacinth.util.DateUtils;
import com.hyacinth.util.validator.annotation.FieldMeta;
import org.apache.commons.lang.StringUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


/**
 * 平台校验工程类
 *
 * @author zhangfb
 * @version 1.0.0.1
 */
public class HyValidatorFactory {

    private static Validator validator; // 它是线程安全的
    private static Map<Class<?>, Map<String, String>> classFieldMetaMap = new HashMap<>();

    static {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }

    public static <T> void validate(T t) {
        Set<ConstraintViolation<T>> constraintViolations = validator.validate(t);
        if (constraintViolations.size() > 0) {
            for (ConstraintViolation<T> constraintViolation : constraintViolations) {
                String fName = getFieldMeta(t.getClass(), constraintViolation.getPropertyPath().toString());
                throw new IllegalArgumentException(fName + constraintViolation.getMessage());
            }
        }
        // 注解解析
        analyBase(t);
    }

    /**
     * 注解解析
     */
    private static <T> void analyBase(T t) {
        if (t == null) {
            throw new BusinessException(ErrorCodeEnum.GL99990001);
        }
        Field[] fields = t.getClass().getDeclaredFields();
        for (Field f : fields) {
            try {
                FieldMeta fm = f.getAnnotation(FieldMeta.class);
                if (fm == null) {
                    continue;
                }
                f.setAccessible(true);
                String filedVal = String.valueOf(f.get(t)); //字段值
                String fmVal = fm.value(); //注解默认值
                if (!fmVal.isEmpty() && (StringUtils.isBlank(filedVal) || "null".equals(filedVal))) {
                    if (f.getType() == fmVal.getClass()) {
                        f.set(t, fmVal);
                    } else {
                        if (f.getType() == String.class) {
                            f.set(t, fmVal);
                        } else if (f.getType() == Long.class) {
                            f.set(t, new Long(fmVal));
                        } else if (f.getType() == BigDecimal.class) {
                            f.set(t, new BigDecimal(fmVal));
                        } else if (f.getType() == Integer.class) {
                            f.set(t, new Integer(fmVal));
                        } else if (f.getType() == Double.class) {
                            f.set(t, new Double(fmVal));
                        } else if (f.getType() == Date.class) {
                            f.set(t, DateUtils.parse(fmVal));
                        } else {
                            f.set(t, fmVal);
                        }
                    }
                }
            } catch (IllegalAccessException e) {
                throw new BusinessException(ErrorCodeEnum.GL99990001);
            }
        }
    }

    private static String getFieldMeta(Class<?> type, String name) {
        Map<String, String> fieldMetaMap = classFieldMetaMap.get(type);
        if (fieldMetaMap == null) {
            fieldMetaMap = new HashMap<>();
            Field[] fields = type.getDeclaredFields();
            for (Field f : fields) {
                FieldMeta fm = f.getAnnotation(FieldMeta.class);
                if (fm != null && !fm.name().isEmpty()) {
                    fieldMetaMap.put(f.getName(), fm.name());
                } else if (fm != null && !fm.param().isEmpty()) {
                    fieldMetaMap.put(f.getName(), fm.param());
                } else {
                    fieldMetaMap.put(f.getName(), f.getName());
                }
            }
            classFieldMetaMap.put(type, fieldMetaMap);
        }
        return fieldMetaMap.get(name);
    }

}
